<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>27.聚光灯</title>
	<style>
		canvas {
            background-color: rebeccapurple;
		}
	</style>
	<script src="../utils/index.js"></script>
	<link rel="stylesheet" href="../utils/ui.css">
</head>
<body>
	<div id="ui">
		<div class="x"></div>
		<div class="y"></div>
		<div class="z"></div>
		<div class="scaleX"></div>
		<div class="scaleY"></div>
		<div class="scaleZ"></div>
		<div class="rotateX"></div>
		<div class="rotateY"></div>
		<div class="rotateZ"></div>
		<div class="lightX"></div>
		<div class="lightY"></div>
		<div class="lightZ"></div>
	</div>
	<canvas id="gl" style="background-color: rebeccapurple;"></canvas>
	<script type="x-shader/x-vertex" id="vertex">
		uniform mat4 u_matrix;
		uniform vec3 u_light;
		uniform mat4 u_worldInverseTranspose;

		attribute vec4 a_normal;
		attribute vec4 a_position;

	    varying vec4 v_color;
	    varying vec4 v_normal;
	    varying vec3 v_light;
	    varying vec3 v_position;
		void main(){
			gl_Position=u_matrix*a_position;
			v_normal= mat4( u_worldInverseTranspose ) * a_normal;
			v_light=u_light;
			v_position=gl_Position.xyz;
		}
	</script>
	
	<script type="x-shader/x-fragment" id="fragment">
		precision mediump float;

	    varying vec4 v_normal;
	    varying vec3 v_light;
	    varying vec3 v_position;
		void main(){
			vec3 dotLight=vec3(1.0,1.0,5.0)*100.;
			vec3 normal=normalize(v_normal).xyz;
			vec3 surfaceToLightDirection=normalize(dotLight-(v_position));
			float light2=dot(normal,surfaceToLightDirection);

			vec4 light=vec4(dot(v_light,v_normal.xyz)*vec3(1.,1.0,1.0),1.);
			vec3 c=vec3(0.,0.,800.);
			vec3 surfaceToViewDirection = normalize(c-v_position);
			vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);
		  
			float specular = dot(normal, halfVector);
			vec4 color=vec4(0.,1.,1.,1.);

		   
			float dotFromDirection = dot(surfaceToLightDirection, vec3(-0.3102,-0.1938,-0.930)*1.);
			float inLight =step(0.07, dotFromDirection);
			//smoothstep(lowerBound, upperBound, value)//下，上，值
			float light3 = inLight * dot(normal, surfaceToLightDirection);;
			specular*= inLight;


			float limitRange = 0.3490658503988659-0.17453292519943295 ;
			inLight = clamp((dotFromDirection - 0.17453292519943295) / limitRange, 0.0, 1.0);
			//clamp(myFloat, 0.0, 2.718); // 限制浮点数的取值范围为[0, 2.718]
			float light4 = inLight * dot(normal, surfaceToLightDirection);
			specular = inLight * pow(dot(normal, halfVector), 1.);



			//*(light)
			gl_FragColor =color;
			//gl_FragColor.xyz*=light2;
			gl_FragColor.xyz*=light4;
			gl_FragColor.rgb += specular;
			//传一个cos角度,计算法线和光的方向之间的cos值，在传入值的访问就加上光源
		}
	</script>
	
	<script>
		 /** @type {HTMLCanvasElement} */   
		const canvas=document.getElementById("gl")
		const gl=canvas.getContext("webgl")
		canvas.width=1000
		canvas.height=1000
		//流程 1.创建着色器 编译 链接
		const vertex=document.getElementById("vertex").textContent
		const fragment=document.getElementById("fragment").textContent
		
		const vertexShader=gl.createShader(gl.VERTEX_SHADER)
		const fragmentShader=gl.createShader(gl.FRAGMENT_SHADER)
		gl.shaderSource(vertexShader,vertex)
		gl.shaderSource(fragmentShader,fragment)
		gl.compileShader(vertexShader)
		gl.compileShader(fragmentShader)
		const program=gl.createProgram()
		gl.attachShader(program,vertexShader)
		gl.attachShader(program,fragmentShader)
		gl.linkProgram(program)
		gl.useProgram(program)
		gl.viewport(0,0,1000,1000)


		const u_matrix=gl.getUniformLocation(program,"u_matrix")
		const u_light=gl.getUniformLocation(program,"u_light")
		const u_worldInverseTranspose=gl.getUniformLocation(program,"u_worldInverseTranspose")
		// const u_cameraPosition=gl.getUniformLocation(program,"u_cameraPosition")
		
		
		let m4=webglUtils.Mat4
		let matrix=m4.create()
		gl.uniformMatrix4fv(u_matrix,false,matrix)

		gl.uniform3fv(u_light,[-1,0,0])
		
		const translation=[0,-200,0]
		const scale=[1,1,1]
		let rotate=[0,0,0]
		const centre=[-100,-100,-100]//中心点
		
		const light=[0.4,0.5,0.6]
		{
			
			webglUtils.setupSlider(".x",{
				min:-1000,
				max:1000,
				value:translation[0],
				step:1,
				handle:(e,v)=>{
					translation[0]=v.value
				}
			})
			webglUtils.setupSlider(".y",{
				min:-1000,
				max:1000,
				value:translation[1],
				step:1,
				handle:(e,v)=>{
					translation[1]=v.value
				}
			})
			webglUtils.setupSlider(".z",{
				min:-2000,
				max:0,
				value:translation[2],
				step:1,
				handle:(e,v)=>{
					translation[2]=v.value
				}
			})
			webglUtils.setupSlider(".scaleX",{
				min:-10,
				max:10,
				value:1,
				step:1,
				handle:(e,v)=>{
					scale[0]=v.value
				}
			})
			webglUtils.setupSlider(".scaleY",{
				min:-10,
				max:10,
				value:1,
				step:1,
				handle:(e,v)=>{
					scale[1]=v.value
				}
			})
			webglUtils.setupSlider(".scaleZ",{
				min:-10,
				max:10,
				value:1,
				step:1,
				handle:(e,v)=>{
					scale[2]=v.value
				}
			})
			webglUtils.setupSlider(".rotateX",{
				min:0,
				max:360,
				value:0,
				step:1,
				handle:(e,v)=>{
					rotate[0]=v.value
				}
			})
			webglUtils.setupSlider(".rotateY",{
				min:0,
				max:360,
				value:0,
				step:1,
				handle:(e,v)=>{
					rotate[1]=v.value
				}
			})
			webglUtils.setupSlider(".rotateZ",{
				min:0,
				max:360,
				value:0,
				step:1,
				handle:(e,v)=>{
					rotate[2]=v.value
				}
			})
			webglUtils.setupSlider(".lightX",{
				min:-1,
				max:1,
				value:light[0],
				step:0.01,
				precision:2,
				handle:(e,v)=>{
					light[0]=v.value
				}
			})
			
			webglUtils.setupSlider(".lightY",{
				min:-1,
				max:1,
				value:light[1],
				step:0.01,
				precision:2,
				handle:(e,v)=>{
					light[1]=v.value
				}
			})
			webglUtils.setupSlider(".lightZ",{
				min:-1,
				max:1,
				value:light[2],
				step:0.01,
				precision:2,
				handle:(e,v)=>{
					light[2]=v.value
				}
			})
		}
		const a_position=gl.getAttribLocation(program,"a_position")
		const a_normal=gl.getAttribLocation(program,"a_normal")
		const pos=[
          // left column front
          0,   0,  0,
          0, 150,  0,
          30,   0,  0,
          0, 150,  0,
          30, 150,  0,
          30,   0,  0,

          // top rung front
          30,   0,  0,
          30,  30,  0,
          100,   0,  0,
          30,  30,  0,
          100,  30,  0,
          100,   0,  0,

          // middle rung front
          30,  60,  0,
          30,  90,  0,
          67,  60,  0,
          30,  90,  0,
          67,  90,  0,
          67,  60,  0,

          // left column back
            0,   0,  30,
           30,   0,  30,
            0, 150,  30,
            0, 150,  30,
           30,   0,  30,
           30, 150,  30,

          // top rung back
           30,   0,  30,
          100,   0,  30,
           30,  30,  30,
           30,  30,  30,
          100,   0,  30,
          100,  30,  30,

          // middle rung back
           30,  60,  30,
           67,  60,  30,
           30,  90,  30,
           30,  90,  30,
           67,  60,  30,
           67,  90,  30,

          // top
            0,   0,   0,
          100,   0,   0,
          100,   0,  30,
            0,   0,   0,
          100,   0,  30,
            0,   0,  30,

          // top rung right
          100,   0,   0,
          100,  30,   0,
          100,  30,  30,
          100,   0,   0,
          100,  30,  30,
          100,   0,  30,

          // under top rung
          30,   30,   0,
          30,   30,  30,
          100,  30,  30,
          30,   30,   0,
          100,  30,  30,
          100,  30,   0,

          // between top rung and middle
          30,   30,   0,
          30,   60,  30,
          30,   30,  30,
          30,   30,   0,
          30,   60,   0,
          30,   60,  30,

          // top of middle rung
          30,   60,   0,
          67,   60,  30,
          30,   60,  30,
          30,   60,   0,
          67,   60,   0,
          67,   60,  30,

          // right of middle rung
          67,   60,   0,
          67,   90,  30,
          67,   60,  30,
          67,   60,   0,
          67,   90,   0,
          67,   90,  30,

          // bottom of middle rung.
          30,   90,   0,
          30,   90,  30,
          67,   90,  30,
          30,   90,   0,
          67,   90,  30,
          67,   90,   0,

          // right of bottom
          30,   90,   0,
          30,  150,  30,
          30,   90,  30,
          30,   90,   0,
          30,  150,   0,
          30,  150,  30,

          // bottom
          0,   150,   0,
          0,   150,  30,
          30,  150,  30,
          0,   150,   0,
          30,  150,  30,
          30,  150,   0,

          // left side
          0,   0,   0,
          0,   0,  30,
          0, 150,  30,
          0,   0,   0,
          0, 150,  30,
          0, 150,   0]
		function randomColor(){
			return [255,0,0]
			return [Math.floor(Math.random()*255),Math.floor(Math.random()*255),Math.floor(Math.random()*255)]
		}
		const normal=[
          // left column front
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,

          // top rung front
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,

          // middle rung front
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,
          0, 0, 1,

          // left column back
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,

          // top rung back
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,

          // middle rung back
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,
          0, 0, -1,

          // top
          0, 1, 0,
          0, 1, 0,
          0, 1, 0,
          0, 1, 0,
          0, 1, 0,
          0, 1, 0,

          // top rung right
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,

          // under top rung
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,

          // between top rung and middle
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,

          // top of middle rung
          0, 1, 0,
          0, 1, 0,
          0, 1, 0,
          0, 1, 0,
          0, 1, 0,
          0, 1, 0,

          // right of middle rung
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,

          // bottom of middle rung.
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,

          // right of bottom
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,
          1, 0, 0,

          // bottom
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,
          0, -1, 0,

          // left side
          -1, 0, 0,
          -1, 0, 0,
          -1, 0, 0,
          -1, 0, 0,
          -1, 0, 0,
          -1, 0, 0]
		
		
		const bufferData=gl.createBuffer()
		gl.bindBuffer(gl.ARRAY_BUFFER,bufferData)
		gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pos), gl.STATIC_DRAW)
		gl.enableVertexAttribArray(a_position)
		gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 0, 0)


		const normalData=gl.createBuffer()
		gl.bindBuffer(gl.ARRAY_BUFFER, normalData)
		gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(normal),gl.STATIC_DRAW)
		gl.enableVertexAttribArray(a_normal)
		gl.vertexAttribPointer(a_normal,3,gl.FLOAT,false,0,0)
		let r=0
		function draw(){
			gl.uniform3fv(u_light,light)
			var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
			var zNear =0.01;
			var zFar = 4000;
			var fieldOfViewRadians = webglUtils.degreesToRadians(60);
			matrix = m4.perspective(fieldOfViewRadians, 1, zNear, zFar);
			r+=1
			matrix=m4.translate(matrix,...translation)

			


			gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
			gl.enable(gl.CULL_FACE);
			gl.enable(gl.DEPTH_TEST);
			// var cameraMatrix = m4.inverse(m4.lookAt([0,0,800],[0,0,0],[0,1,0]));
			let camera = [0,0,800];
			let target = [0, 0, 0];
			let up = [0, 1, 0];
			let cameraMatrix = m4.lookAt(camera, target, up);

			let viewMatrix = m4.inverse(cameraMatrix);
			
			// gl.uniformMatrix4fv(u_cameraPosition,false,new Float32Array(cameraMatrix))
			
			/*
				相机位置矩阵cameraMatrix
				世界坐标矩阵matrix
				点光源位置
				平面位置
			*/
			var worldMatrix = m4.yRotation(webglUtils.degreesToRadians(rotate[1]));
			
			// worldMatrix=m4.translateX(worldMatrix,index*300-300)
			// worldMatrix=m4.rotate(worldMatrix,webglUtils.degreesToRadians(rotate[0]),webglUtils.degreesToRadians(rotate[1]),webglUtils.degreesToRadians(rotate[2]))
			// worldMatrix=m4.scale(worldMatrix,...scale)
			var worldInverseMatrix = m4.inverse(worldMatrix);
			var worldInverseTransposeMatrix = m4.transpose(worldInverseMatrix);

			gl.uniformMatrix4fv(u_matrix,false,new Float32Array(worldMatrix))
			gl.uniformMatrix4fv(u_worldInverseTranspose,false,new Float32Array(worldInverseTransposeMatrix))
			for (let index = 0; index < 5; index++) {
				let mv=m4.multiply(matrix,viewMatrix)
				mv=m4.translateX(mv,index*300-300)
				mv=m4.rotate(mv,webglUtils.degreesToRadians(rotate[0]),webglUtils.degreesToRadians(rotate[1]),webglUtils.degreesToRadians(rotate[2]))
				mv=m4.scale(mv,...scale)

				gl.uniformMatrix4fv(u_matrix,false,new Float32Array(mv))
				gl.drawArrays(gl.TRIANGLES, 0, pos.length/3);
			}
			requestAnimationFrame(draw)
		}
		requestAnimationFrame(draw)
	</script>
</body>
</html>
